package com.hugehard.ImageFilter;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;

public class ProcessingService extends Service {
	private NotificationManager mNotificationManager;
	// private Timer mTimer = new Timer();
	// private int counter = 0, incrementBy = 1;
	private static boolean isRunning = false;
	private static boolean isProcessing = false;

	private List<Messenger> mClients = new ArrayList<Messenger>(); // Keeps
																	// track of
																	// all
																	// current
																	// registered
																	// clients.
	public static final int MSG_REGISTER_CLIENT = 1;
	public static final int MSG_UNREGISTER_CLIENT = 2;
	public static final int MSG_SET_BITMAP_VALUE = 3;
	public static final int MSG_SET_INT_VALUE = 4;
	public static final int MSG_STOP_TASK = 5;

	private final Messenger mMessenger = new Messenger(
			new IncomingMessageHandler()); // Target we publish for clients to
											// send messages to IncomingHandler.

	private static final String LOGTAG = "ProcessingService";

	private KuwaharaTask mKuwaharaTask = null;
	private static final int mAreaSize = 3;

	@Override
	public void onCreate() {
		super.onCreate();
		Log.i(LOGTAG, "Service Started.");
		// showNotification();
		// mTimer.scheduleAtFixedRate(new MyTask(), 0, 100L);
		isRunning = true;
	}

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		Log.i(LOGTAG, "Received start id " + startId + ": " + intent);
		return START_STICKY; // Run until explicitly stopped.
	}

	/**
	 * Display a notification in the notification bar.
	 */
	private void showNotification() {
		mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		// In this sample, we'll use the same text for the ticker and the
		// expanded notification
		CharSequence text = getText(R.string.service_started);

		// Set the icon, scrolling text and timestamp
		Notification notification = new Notification(R.drawable.ic_launcher,
				text, System.currentTimeMillis());

		notification.flags |= Notification.FLAG_AUTO_CANCEL;

		// The PendingIntent to launch our activity if the user selects this
		// notification
		Intent intent = new Intent(this, ImageFilterActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
				| Intent.FLAG_ACTIVITY_SINGLE_TOP);
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
				intent, 0);
		// PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
		// new Intent(this, ImageFilterActivity.class)
		// .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
		// | Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

		// Set the info for the views that show in the notification panel.
		notification.setLatestEventInfo(this, getText(R.string.service_label),
				text, contentIntent);

		// Send the notification.
		// We use a layout id because it is a unique number. We use it later to
		// cancel.
		mNotificationManager.notify(R.string.service_started, notification);
	}

	@Override
	public IBinder onBind(Intent intent) {
		Log.i(LOGTAG, "onBind");
		return mMessenger.getBinder();
	}

	/**
	 * Send the data to all clients.
	 * 
	 * @param intvaluetosend
	 *            The value to send.
	 */
	private void sendMessageToUI(int timeCost, Bitmap bitmap) {
		Iterator<Messenger> messengerIterator = mClients.iterator();
		while (messengerIterator.hasNext()) {
			Messenger messenger = messengerIterator.next();
			try {
				messenger.send(Message.obtain(null, MSG_SET_INT_VALUE,
						timeCost, 0));

				Bundle bundle = new Bundle();
				bundle.putParcelable(ImageFilterActivity.KEY_BITMAP, bitmap);

				Message msg = Message.obtain(null, MSG_SET_BITMAP_VALUE);
				msg.setData(bundle);
				messenger.send(msg);

			} catch (RemoteException e) {
				// The client is dead. Remove it from the list.
				mClients.remove(messenger);
			}
		}
	}

	public static boolean isRunning() {
		return isRunning;
	}

	public static boolean isProcessing() {
		return isProcessing;
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// mNotificationManager.cancel(R.string.service_started); // Cancel the
		// // persistent
		// // notification.
		Log.i(LOGTAG, "Service Stopped.");
		isRunning = false;
	}

	// ///////////////////////////////////////
	// Nested classes
	// ///////////////////////////////////////

	/**
	 * Handle incoming messages from ImageFilterActivity
	 */
	private class IncomingMessageHandler extends Handler { // Handler of
															// incoming messages
															// from clients.
		@Override
		public void handleMessage(Message msg) {
			Log.d(LOGTAG, "handleMessage: " + msg.what);
			switch (msg.what) {
			case MSG_REGISTER_CLIENT:
				mClients.add(msg.replyTo);
				break;
			case MSG_UNREGISTER_CLIENT:
				mClients.remove(msg.replyTo);
				break;
			case MSG_SET_BITMAP_VALUE:

				Bundle b = msg.getData();
				Bitmap bitmap = (Bitmap) b
						.getParcelable(ImageFilterActivity.KEY_BITMAP);

				mKuwaharaTask = new KuwaharaTask();
				mKuwaharaTask.execute(bitmap);
				bitmap = null;

				break;
			case MSG_STOP_TASK:
				mKuwaharaTask.cancel(true);
				mKuwaharaTask = null;
				break;
			default:
				super.handleMessage(msg);
			}
		}
	}

	private class KuwaharaTask extends AsyncTask<Bitmap, Integer, Bitmap> {
		private Date mStartTime;
		private Date mEndTime;

		@Override
		protected void onPreExecute() {
			mStartTime = new java.util.Date();
			isProcessing = true;
		}

		@Override
		protected Bitmap doInBackground(Bitmap... params) {
			// Kuwahara kuwa = new Kuwahara();
			// Bitmap postImage = kuwa.kuwaharaFilter(params[0], 3);

			Bitmap chosenImage = params[0];
			
			int width = chosenImage.getWidth();
			int height = chosenImage.getHeight();
			int pixels[] = new int[width * height];
			chosenImage.getPixels(pixels, 0, width, 0, 0, width, height);
			pixels = jnilib.jnimethods.kuwahara(pixels, width, height,
					mAreaSize);
			Bitmap postImage = Bitmap.createBitmap(pixels, width, height,
					Bitmap.Config.RGB_565);
			
			chosenImage = null;
			pixels = null;

			return postImage;
			
//			//no memory leak
//			Kuwahara kuwa = new Kuwahara();
//			chosenImage = kuwa.kuwaharaFilter(chosenImage, 3);
//			kuwa = null;
//			return chosenImage;
		}

		@Override
		protected void onPostExecute(Bitmap bitmap) {
			mEndTime = new java.util.Date();
			int timeCost = (int) (mEndTime.getTime() - mStartTime.getTime());
			sendMessageToUI(timeCost, bitmap);
			if (!ImageFilterActivity.isActivityVisible()) {
				showNotification();
			}
			isProcessing = false;
		}
	}
}